package Manage;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;

import com.hp.hpl.jena.ontology.Individual;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntModelSpec;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.vocabulary.OWL;
import com.hp.hpl.jena.vocabulary.RDF;
import com.hp.hpl.jena.vocabulary.RDFS;
import com.hp.hpl.jena.vocabulary.XSD;

import BasicModel.AtomicModel;
import BasicModel.Element.Component.Port;
import BasicModel.Element.Component.Param;

//singleton pattern
public class ModelMgr {
	private static ModelMgr m_instance = null;
	private OntModel owlModelSave;

	public static String prefix = 
			"prefix rdfs: <"+ RDFS.getURI()+ ">\n"
					+ "prefix owl: <"+ OWL.getURI()+ ">\n"
					+ "prefix rdf: <"+ RDF.getURI()+ ">\n"
					+ "prefix xsd: <"+ XSD.getURI()+ ">\n"
					+ "prefix devsmo: <http://www.semanticweb.org/2015/2/DEVSMO.owl#>\n";

	private LinkedList<AtomicModel> aModelSet = new LinkedList<AtomicModel>();

	private ModelMgr() {

	}

	public static ModelMgr getInstance() {
		if (m_instance == null) {
			m_instance = new ModelMgr();
		}
		if(m_instance.aModelSet != null)
		{
			m_instance.aModelSet.clear();
		}
		return m_instance;
	}

	public void loadModel(File sourceFile) throws FileNotFoundException {

		// TODO : Load all the model ,call the Load of subModel
		//		OntModel owlModel = ModelFactory.createOntologyModel(
		//				OntModelSpec.OWL_MEM_RULE_INF, null);

		OntModel owlModel = ModelFactory.createOntologyModel(
				OntModelSpec.OWL_MEM, null);
		owlModel.read(new FileReader(sourceFile), "");
		//Query the instance of ClassicAtomicModel

		owlModelSave = owlModel;

		//		aModelSet.add(new AtomicModel("CDU_processing_1_model", owlModel));

		//find all CoupledModel
		LinkedList<String> coupledModelList = new LinkedList<String>();
		String queryString = ModelMgr.prefix + "SELECT ?coupledmodel WHERE {?coupledmodel rdf:type devsmo:CoupledModel}";
		QueryExecution qexec = QueryExecutionFactory.create(queryString, owlModel);
		try {
			ResultSet results = qexec.execSelect();
			for(; results.hasNext(); ){
				QuerySolution soln = results.nextSolution();
				RDFNode x= soln.get("coupledmodel");
				Individual coupledmodel_Ins = owlModel.getIndividual(x.toString());
				coupledModelList.add(coupledmodel_Ins.getLocalName());
			}
		} finally{
			qexec.close();
		}
		// traverse the coupledModelList
		for (String coupleModel : coupledModelList)
		{
			queryString = ModelMgr.prefix + "SELECT ?atomicmodel ?component  WHERE {devsmo:" + 
					coupleModel +" devsmo:isComposedOf ?component. ?component devsmo:refersToModel ?atomicmodel}";
			qexec = QueryExecutionFactory.create(queryString, owlModel);
			try {
				ResultSet results = qexec.execSelect();
				for(; results.hasNext(); ){
					QuerySolution soln = results.nextSolution();
					RDFNode atomicModel= soln.get("atomicmodel");
					RDFNode component= soln.get("component");
					Individual atomicModel_Ins = owlModel.getIndividual(atomicModel.toString());
					Individual component_Ins = owlModel.getIndividual(component.toString());
					aModelSet.add(new AtomicModel(atomicModel_Ins.getLocalName(), component_Ins.getLocalName(), owlModel));
				}
			} finally{
				qexec.close();
			}
		}


	}

	public File genNewFile(File pathDir, String fileName)
	{
		String pathStr = null;
		try {
			pathStr = pathDir.getCanonicalPath();
		} catch (IOException e) {
			e.printStackTrace();
		}
		String fileStr = pathStr + "/" + fileName;
		File file = new File(fileStr);
		// create a empty file. if exists() delete it
		if (file.exists()) {
			file.delete();
		}
		try {
			file.createNewFile();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return file;
	}

	public void registerProcess(File path , LinkedList<AtomicModel> aModelSet) throws FileNotFoundException
	{
		File registerFile = genNewFile(path, "register.cpp");
		PrintWriter out = new PrintWriter(registerFile);
		out.println("#include \"modeladm.h\"");
		out.println("#include \"mainsimu.h\"");
		out.println();
		for (AtomicModel temp : aModelSet) {
			out.printf("#include \"../HeadFile/%s.h\"\n", temp.getName());
		}
		out.println();
		out.printf("void MainSimulator::registerNewAtomics()\n");
		out.println("{");
		for (AtomicModel temp : aModelSet) {
			out.printf("\tSingleModelAdm::Instance().registerAtomic( NewAtomicFunction<%s>(), \"%s\");\n", temp.getName(),temp.getName());
		}
		out.println("}");
		out.println();
		out.close();
	}

	public void maFileProcess(File path , LinkedList<AtomicModel> aModelSet) throws FileNotFoundException
	{
		File registerFile = genNewFile(path, "refinery.ma");
		PrintWriter out = new PrintWriter(registerFile);
		out.println("[top]");
		out.println("components :");
		out.println();
		int num = 0;
		// components
		for (AtomicModel temp : aModelSet) {
			//			out.printf("%s_c@%s", temp.getComponentName(), temp.getName());
			//			out.printf((num++ % 10 == 9? "\n" : " "));
			out.printf("%s_c@%s\n", temp.getComponentName(), temp.getName());
		}
		out.println();
		// in
		//		owlModelSave			

		//link
		out.println();
		String queryStr = ModelMgr.prefix + "SELECT ?movement ?fromPort ?fromNode ?toPort ?toNode " +
				"Where {?movement rdf:type devsmo:IC. ?movement devsmo:fromPort ?fromPort. " + 
				"?movement devsmo:fromNode ?fromNode. ?movement devsmo:toPort ?toPort. ?movement devsmo:toNode ?toNode}";
		QueryExecution qexec = QueryExecutionFactory.create(queryStr, owlModelSave);
		try {
			ResultSet results = qexec.execSelect();
			for (; results.hasNext();) {
				QuerySolution soln = results.nextSolution();
				RDFNode fromPort = soln.get("fromPort");
				RDFNode fromNode = soln.get("fromNode");
				RDFNode toPort = soln.get("toPort");
				RDFNode toNode = soln.get("toNode");
				Individual fromPort_Ins = owlModelSave.getIndividual(fromPort
						.toString());
				Individual fromNode_Ins = owlModelSave.getIndividual(fromNode
						.toString());
				Individual toPort_Ins = owlModelSave.getIndividual(toPort
						.toString());
				Individual toNode_Ins = owlModelSave.getIndividual(toNode
						.toString());
				out.printf("Link : %s@%s_c %s@%s_c\n", fromPort_Ins.getLocalName(), fromNode_Ins.getLocalName(), toPort_Ins.getLocalName(), toNode_Ins.getLocalName());
			}
		} finally {
			qexec.close();
		}		
		out.println();


		//yield param
		for (AtomicModel atmodel : aModelSet) {
			if (atmodel.getYieldSet().getparamSet().size() > 0)
			{
				out.printf("[%s]\n", atmodel.getComponentName() + "_c");
				for(Param param : atmodel.getYieldSet().getparamSet())
				{
					out.printf("%s : %s\n",param.getSignalVar().getName(), param.getParamValue());
				}
			}
		}
		
		out.println();
		out.println();
		
		//getOptFlowrate param
		for (AtomicModel atmodel : aModelSet) {
			if (atmodel.getOptFlowrateSet().getparamSet().size() > 0)
			{
				out.printf("[%s]\n", atmodel.getComponentName() + "_c");
				for(Param param : atmodel.getOptFlowrateSet().getparamSet())
				{
					out.printf("%s : %s\n",param.getSignalVar().getName(), param.getParamValue());
				}
			}
		}

		out.println();
		out.println();
		out.close();
	}


	public void generateModel(String targetDir) throws FileNotFoundException {
		File headFileDir = new File(targetDir + "\\HeadFile");
		File cppFileDir = new File(targetDir + "\\CppFile");
		File javaFileDir = new File(targetDir + "\\JavaFile");

		File targetPath;	
		if (!headFileDir.exists()) {
			headFileDir.mkdirs();
		}

		if (!cppFileDir.exists()) {

			cppFileDir.mkdirs();
		}


		for (AtomicModel temp : aModelSet) {

			temp.WriteH(headFileDir);
			temp.WriteCpp(cppFileDir);
//			temp.WriteJava(javaFileDir);
		}
		registerProcess(cppFileDir , aModelSet);
		maFileProcess(cppFileDir , aModelSet);

		Runtime runtime = Runtime.getRuntime();
		try {
			String path = System.getProperty("user.dir");
			//			runtime.exec("cmd /c "+ path +"\\Util\\astyle --style=allman --suffix=none "+path+"\\Model\\*.h "+path+"\\Model\\*.cpp");
			runtime.exec("cmd /c "+ path +"\\Util\\astyle --style=allman --suffix=none "+path+"\\Model\\*.h");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

}
